﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Windows;

namespace ScriptBox
{
    public class TalonsUpdate
    {
        private const int RequestTimeout = 15;
        private static readonly HttpClient _httpClient = new HttpClient();

        public string NewVersion { get; private set; }
        private string Owner { get; }
        private string Repo { get; }
        private string UpdateUrl { get; set; }

        public event EventHandler<string> UpdateChecked;
        WindowUpdate updateWin;

        public TalonsUpdate(string owner, string repo)
        {
            Owner = owner;
            Repo = repo;
            _httpClient.Timeout = TimeSpan.FromSeconds(RequestTimeout);
            _httpClient.DefaultRequestHeaders.Add("User-Agent", "ScriptBox Update Checker");
        }

        /// <summary>
        /// 检查更新
        /// </summary>
        /// <param name="currentVersion">当前版本号</param>
        public void CheckUpdate(string currentVersion)
        {
            Task.Run(async () =>
            {
                try
                {
                    NewVersion = await GetLatestVersion_Gitee(Owner, Repo);
                    bool hasUpdate = NewVersion != null &&
                        Version.Parse(NewVersion) > Version.Parse(currentVersion);

                    if (hasUpdate)
                    {
                        UpdateChecked?.Invoke(this, NewVersion);
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"检查更新失败: {ex.Message}");
                    UpdateChecked?.Invoke(this, null);
                }
            });
        }

        /// <summary>
        /// 获取gitee仓库最新版本号
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="repo"></param>
        /// <returns></returns>
        private async Task<string> GetLatestVersion_Gitee(string owner, string repo)
        {
            try
            {
                string apiUrl = $"https://gitee.com/api/v5/repos/{owner}/{repo}/releases/latest";
                
                var response = await _httpClient.GetAsync(apiUrl);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                var release = JObject.Parse(json);
                
                var tag = release["tag_name"]?.ToString();
                if (string.IsNullOrEmpty(tag))
                    throw new FormatException("无效的版本标签");

                //解析下载链接
                foreach (JObject asset in release["assets"])
                {
                    string downloadUrl = (string)asset["browser_download_url"];
                    if(downloadUrl.Contains("exe"))
                    {
                        UpdateUrl = downloadUrl;
                    }
                }

                return tag.StartsWith("V", StringComparison.OrdinalIgnoreCase) ? tag.Substring(1) : tag;
            }
            catch (HttpRequestException ex)
            {
                throw new ApplicationException($"HTTP请求失败: {ex.StatusCode}", ex);
            }
            catch (JsonException ex)
            {
                throw new ApplicationException("JSON解析失败", ex);
            }
        }
        /// <summary>
        /// 用默认浏览器访问仓库release页面
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="repo"></param>
        public void OpenRepoRelease_Gitee()
        {
            OpenRepoRelease_Gitee(Owner, Repo);
        }
        /// <summary>
        /// 用默认浏览器访问仓库release页面
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="repo"></param>
        public void OpenRepoRelease_Gitee(string owner, string repo)
        {
            string url = string.Format("https://gitee.com/{0}/{1}/releases", owner, repo);
            System.Diagnostics.Process.Start(url);
        }

        /// <summary>
        /// 开始更新
        /// </summary>
        public void StartUpdate()
        {
            string filePath = String.Empty;
            updateWin = new WindowUpdate(NewVersion);
            updateWin.Show();

            var progress = new Progress<int>(p => {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    updateWin.ProgressBar_Update.Value = p;
                    updateWin.Label_UpdateState.Content = $"下载中：{p}%";
                });
            });
            Task.Run(async () => {
                try {
                    filePath = await DownloadFileAsync(UpdateUrl, Path.GetTempPath(), progress);
                    Application.Current.Dispatcher.Invoke(() => {
                        updateWin.Close();
                        Process.Start(filePath);
                    });
                }
                catch (OperationCanceledException) {
                    if (File.Exists(filePath))
                        File.Delete(filePath);
                }
                catch (Exception ex) {
                    Application.Current.Dispatcher.Invoke(() => {
                        MessageBox.Show(ex.Message, "下载失败");
                        updateWin.Close();
                    });
                }
            });
        }
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="savePath"></param>
        public async Task<string> DownloadFileAsync(string url, string savePath, IProgress<int> progress)
        {
            try
            {
                using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
                response.EnsureSuccessStatusCode();

                var fileName = Path.GetFileName(new Uri(url).AbsolutePath);
                var filePath = Path.Combine(savePath, fileName);

                using var stream = await response.Content.ReadAsStreamAsync();
                using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);

                var totalBytes = response.Content.Headers.ContentLength ?? -1L;
                var buffer = new byte[81920];
                var bytesRead = 0;
                var totalRead = 0L;

                while ((bytesRead = await stream.ReadAsync(buffer)) > 0)
                {
                    await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead));
                    totalRead += bytesRead;

                    if (totalBytes > 0)
                        progress?.Report((int)(totalRead * 100 / totalBytes));
                }
                return filePath;
            }
            catch (HttpRequestException ex)
            {
                throw new ApplicationException($"HTTP错误: {ex.StatusCode}", ex);
            }
            catch (IOException ex)
            {
                throw new ApplicationException("文件写入失败，请检查权限", ex);
            }
        }
    }
}